using UnityEngine;
using System.Collections;
using System.Collections.Generic;

using System;

/*! @brief An octave represent a function used for noise value generation, can have desired dimension        */
public class Octave
{
    public float[]  m_Values;               /*!< Values of the Octave to be interpolated                        */
    public int      m_Seed;                 /*!< Seed Value used to construct the Octave                        */

    public float    m_Amplitude;            /*!< "Max" value of the function    */
    public int      m_WaveLength;           /*!< "Max" value of the function    */

    public Octave(int seed, float amplitude, int waveLength)
    {
        m_Seed = seed;
        m_WaveLength = waveLength;
        m_Amplitude = amplitude;


        // I initialize my Pseudo random generator with the seed. The goal of the seed is to get back the same number each time we 
        // reseed the random func

        System.Random random = new System.Random(seed);

        m_Values = new float[m_WaveLength];

        for (int i = 0; i < m_WaveLength; i++)
        {
            m_Values[i] = ((float)random.Next(0, 100) / 100.0f) * (float)m_Amplitude;
        }
    }

  

    /*! @brief This function will return the interpolated height between the a and b vertex of the current octave   */
    public float Interpolation(float a, float b, float t)
    {
        return (a * (1-t)+ b*t);
    }

    public float Interpolation2D(float a, float b, float c, float d, float u, float v)
    {
        float y1    =   Interpolation(a, b, u);
        float y2    =   Interpolation(c, d, u);

        return Interpolation(y1, y2, v);
    }
}



public class RandomTexture : MonoBehaviour 
{
    public int m_OctaveCount;
    public int m_Values;        /*!< Number of values for the first octave  */

    public int m_Width;
    public int m_Height;

    public int m_Seed;
    public int m_Dimension;

    private  float m_MaxInterval=0.0f;


    public Texture2D m_NoiseTexture;

   


	// Use this for initialization

    public static Texture2D CreateTexture( int width, int height, int octaveCount, float maxInterval, int valueSize, int seed )
    {
        List<Octave> m_Octaves= new List<Octave>();
        Texture2D m_NoiseTexture = new Texture2D(width, height);
        m_NoiseTexture.filterMode = FilterMode.Point;

        for (int i = 0; i < octaveCount; i++)
        {
            maxInterval += (1.0f / Mathf.Pow(2, i)) * 100.0f;

            Octave octave = new Octave(seed, (1.0f / Mathf.Pow(2, i)) * 100.0f, (int)(Mathf.Pow(valueSize + i, 2)));

            m_Octaves.Add(octave);
        }




        float sumVertex = height * width;

        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                float u = (float)j / (float)width;
                float v = (float)i / (float)height;

                float sum = 0.0f;


                foreach (Octave octave in m_Octaves)
                {
                    int vMin, vMax, uMin, uMax; /*! Point on the octave */

                    vMin = Mathf.FloorToInt(v * (Mathf.Sqrt(octave.m_Values.Length) - 1));
                    vMax = Mathf.CeilToInt(v * (Mathf.Sqrt(octave.m_Values.Length) - 1));

                    uMax = Mathf.CeilToInt(u * (Mathf.Sqrt(octave.m_Values.Length) - 1));
                    uMin = Mathf.FloorToInt(u * (Mathf.Sqrt(octave.m_Values.Length) - 1));

                    float a, b, c, d;


                    a = octave.m_Values[vMin * (int)(Mathf.Sqrt(octave.m_Values.Length)) + uMin];
                    b = octave.m_Values[vMin * (int)(Mathf.Sqrt(octave.m_Values.Length)) + uMax];

                    c = octave.m_Values[vMax * (int)(Mathf.Sqrt(octave.m_Values.Length)) + uMin];
                    d = octave.m_Values[vMax * (int)(Mathf.Sqrt(octave.m_Values.Length)) + uMax];

                    float caseWidth = 1.0f / (Mathf.Sqrt(octave.m_Values.Length) - 1.0f);
                    sum += octave.Interpolation2D(a, b, c, d, (u - (uMin * caseWidth)) * (1.0f / caseWidth),
                        (v - (vMin * caseWidth)) * (1.0f / caseWidth));
                }
                float val = sum / maxInterval;
                m_NoiseTexture.SetPixel(j, i, new Color(val, val, val, 1.0f));
            }
        }
        m_NoiseTexture.Apply();


        return m_NoiseTexture;

    }

	void Start () 
    {
         this.renderer.material.mainTexture =CreateTexture(m_Width, m_Height, m_OctaveCount, m_MaxInterval, m_Values, m_Seed);
	}


    void CreateTexture(int seed)
    {
    }
    // Update is called once per frame
    void Update() 
    {
	
	}
}
